resource.AddFile("sound/StargateExtras/charge2.wav")
resource.AddFile("sound/StargateExtras/hum3.wav")
resource.AddFile("models/naquadah_bomb/bomb.mdl")

AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")

include("shared.lua")

ENT.SoundPaths = {}
ENT.SoundPaths["charge_start"] = Sound("StargateExtras/charge2.wav")
ENT.SoundPaths["charge_ambient"] = Sound("StargateExtras/hum3.wav")
ENT.SoundPaths["code_accepted"] = Sound("buttons/button9.wav")
ENT.SoundPaths["code_rejected"] = Sound("buttons/button8.wav")

ENT.Sounds = {}

function ENT:SpawnFunction(pl,tr)
	if !tr.Hit then return end
	local bomb = ents.Create(self:GetClass())
	bomb:SetPos(tr.HitPos + tr.HitNormal * 38)
  bomb:SetVar("Owner", pl)
	bomb:Spawn()
	bomb:Activate()
   
	undo.Create(self:GetClass())
		undo.AddEntity(bomb)
		undo.SetPlayer(pl)
	undo.Finish()
end

function ENT:Initialize()         
  -- Bomb starts disarmed
  self:SetNWInt("State", 1) --  1 = Idle ,  2 = Armed,  3 = Charging
  self.charge = 0
    
  -- Set health
  self.Entity:SetMaxHealth(100)
  self.Entity:SetHealth(100)
    
  self.Entity:SetModel("models/naquadah_bomb/bomb.mdl")
    
  -- Set up physics for entity
  local thisPhysics = self.Entity:GetPhysicsObject()
    
  self.Entity:PhysicsInit(SOLID_VPHYSICS)
	self.Entity:SetMoveType(MOVETYPE_VPHYSICS)
	self.Entity:SetSolid(SOLID_VPHYSICS)
    
	if(thisPhysics:IsValid()) then
		thisPhysics:Wake()
		thisPhysics:SetMass(2500)
	end
    
  -- Set resources
  if(self.HasRD) then
    self:AddResource("energy", self.energyRequired)
  end
    
   -- Set up wire inputs and outputs
	if(self.HasWire) then 
		self:CreateWireInputs("Detonation Code", "Abort") 
		self:CreateWireOutputs("Charging", "Charge") 
	end
   
	self.Sounds["ambient"] = CreateSound(self.Entity, self.SoundPaths["charge_ambient"])
end

function ENT:Setup(detonationCode, abortCode,  yield, chargeTime)
   if(self.charging) then
      return false
   end

	--DebugMsg("Setup detCode: "..tostring(detonationCode).." Abort: "..tostring(abortCode).."\n")
   self.detonationCode = detonationCode or "1"
   self.abortCode = abortCode or "2"
   self.yield = math.Clamp(yield, 10, 100)
   self.chargeTime = math.max(chargeTime, 10)
   self.energyRequired = math.max(360000 * self.yield / self.chargeTime, 6000000)

   if(self.HasWire) then
      self:SetWire("Charging", 0)
      self:SetWire("Charge", 0)
   end
   
   return true
end

function ENT:TriggerInput(inputName, inputValue)
    if(self.malfunctioning ~= true) then
        if(inputName == "Detonation Code") then
            self:StartDetonation(tostring(inputValue))
        elseif(inputName == "Abort") then
            self:AbortDetonation(tostring(inputValue))
        end
    end
end

function ENT:StartDetonation(code)
   if(self:GetNWInt("State", 1) == 3) then
		return true
   end
   
   if( not self:IsDetonationCode(code)) then
      return false
   end
   
	if(!self.HasRD || 
      self:GetResource("energy") >= self.energyRequired) then
      
      self:SetNWInt("State", 3)
      
      if(self.HasWire) then
         self:SetWire("Charging", 1)
      end
      
      self.Entity:EmitSound(self.SoundPaths["charge_start"])
      self.Sounds["ambient"]:Play()
      
      return true
   end
end

function ENT:AbortDetonation(code)
	if(self:GetNWInt("State", 1) ~= 3) then
		return true
   end
   
   if( not self:IsAbortCode(code)) then
      return false
   end
   
	if(not self.malfunctioning) then
      self:SetNWInt("State", 2)
      self.charge = 0
        
      if(self.HasWire) then
         self:SetWire("Charging", 0)
         self:SetWire("Charge", self.charge)
      end
      
      self.Entity:StopSound(self.SoundPaths["charge_start"])
      self.Sounds["ambient"]:Stop()
        
      return true
   end
end

function ENT:IsDetonationCode(code)
   if(code == self.detonationCode) then
      self.Entity:EmitSound(self.SoundPaths["code_accepted"])
      return true
   else
      self.Entity:EmitSound(self.SoundPaths["code_rejected"])
      return false
   end
end

function ENT:IsAbortCode(code)
	if(code == self.abortCode) then
		self.Entity:EmitSound(self.SoundPaths["code_accepted"])
		return true
	else
		self.Entity:EmitSound(self.SoundPaths["code_rejected"])
		return false
	end
end

-- Make local to avoid overriding any identically named functions in other scripts
local function ReceiveDetonationCommand(Player, command, args)
   local bomb = ents.GetByIndex(args[1])
   
   --DebugMsg("naquadah_bomb: Received Detonation Code: "..args[2].."\n")
   if(bomb and bomb.StartDetonation) then
      bomb:StartDetonation(args[2])
   end
end

concommand.Add("StartDetonation", ReceiveDetonationCommand)

-- Make local to avoid overriding any identically named functions in other scripts
local function ReceiveAbortCommand(Player, command, args)
   local bomb = ents.GetByIndex(args[1])
   
   --DebugMsg("naquadah_bomb: Received Abort Code: "..args[2].."\n")
   if(bomb and bomb.AbortDetonation) then
      bomb:AbortDetonation(args[2])
   end
end

concommand.Add("AbortDetonation", ReceiveAbortCommand)

function ENT:OnTakeDamage(damageInfo)
    if self:GetNWInt("State", 1) == 4 then return end
	self.Entity:SetHealth(self.Entity:Health() - damageInfo:GetDamage())
       
    if(self.Entity:Health() <= 0) then
        self:Destruct()
    end
end

function ENT:Damage()
   local effectInfo = EffectData()
   effectInfo:SetStart(self.Entity:GetPos())
   
   util.Effect("StunstickImpact", effectInfo)
end

function ENT:Repair()
    self.Entity:SetHealth(self.Entity:GetMaxHealth())
end

-- Destroy bomb (without detonating warhead)
function ENT:Destruct()
   -- Make bomb explode (without warhead detonation)
	self:SetNWInt("State", 4)
	
	self.Entity:Remove()
	destructEffect = EffectData()
	destructEffect:SetOrigin(self.Entity:GetPos())
	destructEffect:SetScale(1 + (self.charge / 100))
	destructEffect:SetMagnitude(50 + self.charge)
	util.Effect("Explosion", destructEffect, true, true)
	
	local bombOwner = self.Entity:GetVar("Owner", self.Entity)
	local blastRadius = 100 + (self.charge * 5)
	local blastDamage = 50 + self.charge
	util.BlastDamage(self.Entity, bombOwner, self.Entity:GetPos(), blastRadius, blastDamage)   
end

-- Detonate warhead
function ENT:Detonate()
   local warhead = ents.Create("gate_nuke")
   
   if(warhead ~= nil and warhead:IsValid()) then
      warhead:Setup(self.Entity:GetPos(), self.yield)
      warhead:SetVar("owner",self.Owner)
      warhead:Spawn()
      warhead:Activate()
   end
   
   self.Entity:Remove()
end

function ENT:ShakeCamera(strength, duration, radius)
   local shake = ents.Create("env_shake")
	
   shake:SetKeyValue("amplitude", strength)
	shake:SetKeyValue("duration", duration)
	shake:SetKeyValue("radius", radius) 
	shake:SetKeyValue("frequency", "240")
	shake:SetPos(self.Entity:GetPos())
    
	shake:Spawn()
	shake:Fire("StartShake","","0")
	shake:Fire("kill", "", duration + 2)
end

function ENT:OnRemove()
  self.Sounds["ambient"]:Stop()
   
  StarGate.WireRD.OnRemove(self)
end

function ENT:Think()
   local energyDeficit = 0
   
   if(self.HasRD) then
      energyDeficit = self.energyRequired - self:GetResource("energy")
   end
   
   if(self:GetNWInt("State", 1) == 3) then
      self:SetOverlayText("Charging!")
                
      self:Charge()
   elseif(self.malfunctioned) then
      self:StartDetonation()
   elseif(energyDeficit <= 0) then
      self:SetOverlayText("Armed")
   else
      self:SetOverlayText(energyDeficit .. " Energy Required")
   end
    
   if(self.Entity:Health() < self.Entity:GetMaxHealth()) then
      if(self.Entity:Health() <= 0) then
         self:Destruct()
      elseif(math.random(1, self.Entity:Health()) == 1) then
         self.malfunctioned = true
      end
    
      -- Display damage effects
      self:Damage()
   end
    
	self.Entity:NextThink(CurTime() + 1)
   return true
end

function ENT:Charge()
   if(self.charge >= 100) then
      self:Detonate()
      return
   end
   
   if(self.HasRD) then
      local energy = self:GetResource("energy")
      local energyDrain = self.energyRequired / self.chargeTime
    
      if(energy < energyDrain) then
         self:AbortDetonation()
         return false
      end
      
      self:ConsumeResource("energy", energyDrain)
   end
   
   self.charge = self.charge + (100 / self.chargeTime)
   
   if(self.HasWire) then
      self:SetWire("Charge", self.charge)
   end
        
   self:ShakeCamera(16 * (self.charge / 100), 
                    1, 
                    (self.yield * 50) * (self.charge / 100))
                    
   return true
end

function ENT:AcceptInput(inputType, activator, caller)
	if(inputType == "Use" &&
      caller:IsPlayer() &&
      caller:KeyDownLast(IN_USE) == false) then
      
      umsg.Start("naquadah_bomb", caller)
      umsg.Bool(true)
      umsg.End()
	end
end
